<!--
 * @Author: monet hanxu@huaun.com
 * @Date: 2023-09-14 15:33:48
 * @LastEditors: zhangyonggui
 * @LastEditTime: 2023-12-20 10:43:12
 * @FilePath: /h-radar-expose/pages/Exposure/ExposeList/WebDetial.vue
 * @Description: 信息系统详情页面
-->
<template>
  <Detail
    :title-btn="titleBtn"
    :left-num="2"
    :head-num="3"
    :tabs-list="tabsList"
    :tab-active="tabActive"
    @showPrompt="showPrompt"
  >
    <!-- 左侧 -->
    <template #title>
      <el-tooltip effect="dark" :content="basicInfo.name" placement="bottom">
        <span>{{ basicInfo.name }}</span>
      </el-tooltip>
    </template>
    <template #content-title-1>基本信息</template>
    <template #content-body-1>
      <LayoutInfoList :info-list="infoList"></LayoutInfoList>
    </template>
    <template #content-title-2>标签</template>
    <template #content-body-2>
      <TagManip
        :dynamic-tags="basicInfo.tag"
        @handleClose="delTag"
        @handleAdd="addTag"
      ></TagManip>
    </template>
    <!--右侧 -->
    <template #right-head>
      <AssessmentBlock :block-list="blockList"></AssessmentBlock>
    </template>
    <template #tab-content-assetProfile>
      <LayoutDraw :left-num="3">
        <template #content-title-1>基础信息</template>
        <template #content-body-1>
          <el-row class="base-one">
            <el-col :span="8">
              <ModelList :model-list="modelList"></ModelList>
            </el-col>
            <el-col :span="16">
              <ShowCode v-if="headersInfo.code" :code-info="headersInfo">
              </ShowCode>
              <noData v-else class="no-data"></noData>
            </el-col>
          </el-row>
          <el-table
            :data="detialInfo.products"
            class="info-table"
            max-height="324"
          >
            <el-table-column prop="productName" sortable label="产品名称">
              <template v-slot:default="scope">
                {{ scope.row.productName || '--' }}
              </template>
            </el-table-column>
            <el-table-column prop="productCategory" sortable label="产品类型">
              <template v-slot:default="scope">
                {{ scope.row.productCategory || '--' }}
              </template>
            </el-table-column>
          </el-table>
          <LayoutFormList
            :form-list="baseInfo"
            :row-list="rowList"
          ></LayoutFormList>
          <LayoutExpandableBox
            v-for="(item1, index) in expandableList2"
            :key="index"
            :expandable-info="item1"
          >
            <template #content="{ slotContent }">
              <el-tree :data="dirList" :props="defaultProps"></el-tree>
            </template>
          </LayoutExpandableBox>
        </template>
        <template #content-title-2>数字证书信息</template>
        <template #content-body-2>
          <LayoutExpandableBox
            v-for="(item1, index) in expandableList"
            :key="index"
            :expandable-info="item1"
          >
            <template #content="{ slotContent }">
              <ShowCode
                :code-info="{
                  code: slotContent,
                }"
                class="cert-container"
              >
              </ShowCode>
            </template>
          </LayoutExpandableBox>
        </template>
        <template #content-title-3>域名ICP备案信息</template>
        <template #content-body-3>
          <LayoutFormList :form-list="icpInfo"></LayoutFormList>
        </template>
        <template #right-title>资产变更记录</template>
        <template #right-body>
          <LayoutNoticeList :notice-list="noticeList"></LayoutNoticeList>
        </template>
      </LayoutDraw>
    </template>
    <template #tab-content-exposurePath>
      <GraphExposurePath :row-list="rowList"></GraphExposurePath>
    </template>
    <template #tab-content-associatedExposure>
      <GraphExposureSurface :row-list="rowList"></GraphExposureSurface>
    </template>
    <template #tab-content-surfaceAnalysis>
      <LayoutDraw :left-num="2" :left-span="24" :right-span="0">
        <template #content-title-1>资产攻击面图谱</template>
        <template #content-body-1>
          <GraphSurfaceAnalysis :row-list="rowList"></GraphSurfaceAnalysis>
        </template>
        <template #content-title-2>资产弱点</template>
        <template #content-body-2>
          <!-- <vul-table ref="table" v-bind="tableConfig"></vul-table> -->
          <el-table
            class="surfaceAnalysisTable"
            :data="surfaceAnalysisConfig.tableData"
            style="width: 100%"
          >
            <el-table-column prop="vulName" label="弱点名称">
              <template v-slot:default="scope">
                <el-tooltip
                  v-if="scope.row.vulName"
                  effect="dark"
                  :content="scope.row.vulName"
                  placement="top"
                >
                  <p
                    class="over-flow contentStyle"
                    @click="vulNameClick(scope.row)"
                  >
                    {{ scope.row.vulName }}
                  </p>
                </el-tooltip>
                <p v-else>--</p>
              </template>
            </el-table-column>
            <el-table-column prop="vulCode" label="漏洞编号">
              <template v-slot:default="scope">
                <el-tooltip
                  effect="dark"
                  :content="scope.row.vulCode"
                  placement="top"
                >
                  <p class="over-flow">
                    {{ scope.row.vulCode || '--' }}
                  </p>
                </el-tooltip>
              </template>
            </el-table-column>
            <el-table-column prop="vulLevel" label="风险等级">
              <template v-slot:default="scope">
                <p class="over-flow">
                  {{ vulLevelData[scope.row.vulLevel] }}
                </p>
              </template>
            </el-table-column>
            <el-table-column prop="asmType" label="弱点类型">
              <template v-slot:default="scope">
                <p class="over-flow">
                  {{ scope.row.asmType || '--' }}
                </p>
              </template>
            </el-table-column>
            <el-table-column prop="insertTime" label="发现时间">
              <template v-slot:default="scope">
                <el-tooltip
                  effect="dark"
                  :content="scope.row.insertTime"
                  placement="top"
                >
                  <p class="over-flow">
                    {{ scope.row.insertTime || '--' }}
                  </p>
                </el-tooltip>
              </template>
            </el-table-column>
            <el-table-column prop="bugUrl" label="弱点存在位置">
              <template v-slot:default="scope">
                <el-tooltip
                  effect="dark"
                  :content="scope.row.bugUrl"
                  placement="top"
                >
                  <p class="over-flow">
                    {{ scope.row.bugUrl || '--' }}
                  </p>
                </el-tooltip>
              </template>
            </el-table-column>
          </el-table>
          <!-- <el-pagination layout="prev, pager, next" :total="surfaceAnalysisConfig.total" /> -->
          <el-pagination
            class="self-pagination"
            size="small"
            :current-page="surfaceAnalysisConfig.pageNumber"
            :page-size="surfaceAnalysisConfig.pageSize"
            :page-sizes="[5, 10, 15, 20, 50, 100]"
            :layout="'total, sizes, prev, pager, next, jumper'"
            :total="surfaceAnalysisConfig.total"
            @size-change="handleSizeChange"
            @current-change="handleCurrentChange"
          >
          </el-pagination>
        </template>
      </LayoutDraw>
    </template>
  </Detail>
</template>
<script lang="ts" setup>
import Detail from '@/components/Expose/Layout/Detail.vue';
import LayoutInfoList from '@/components/Expose/Layout/InfoList.vue';
import LayoutFormList from '@/components/Expose/Layout/FormList.vue';
import LayoutExpandableBox from '@/components/Expose/Layout/ExpandableBox.vue';
import LayoutNoticeList from '@/components/Expose/Layout/NoticeList.vue';
import LayoutDraw from '@/components/Expose/Layout/Draw.vue';
import GraphExposurePath from '@/components/Expose/Graph/ExposurePath.vue';
import GraphExposureSurface from '@/components/Expose/Graph/ExposureSurface.vue';
import GraphSurfaceAnalysis from '@/components/Expose/Graph/SurfaceAnalysis.vue';
import ModelList from '@/components/Expose/ModelList.vue';
import TagManip from '@/components/Expose/TagManip.vue';
import AssessmentBlock from '@/components/Expose/AssessmentBlock.vue';
import ShowCode from '@/components/Expose/ShowCode.vue';
import noData from '@/components/Expose/noData.vue';
import { usewebDetail } from '@/composables/Expose/usewebDetail';
import { computed, onMounted, reactive, ref } from 'vue';
import { useStore } from 'vuex';
import { useRoute, useRouter } from 'vue-router';
const {
  detialInfo,
  basicInfo,
  delTag,
  addTag,
  showPrompt,
  category,
  blockList,
  changeList,
  getDetialById,
  getLeftBaseInfo,
  getAssetChanged,
  getAnalysis,
} = usewebDetail();
const store = useStore();
const route = useRoute();
const router = useRouter();
const id = ref(route.query.id || '');
const certList = ref([]);
const icpDetail = ref<any>({});
const tabActive = ref('assetProfile');
const tabsList = ref([
  {
    name: 'assetProfile',
    label: '资产画像',
    disabled: false,
  },
  {
    name: 'exposurePath',
    label: '资产暴露路径',
    disabled: false,
  },
  {
    name: 'associatedExposure',
    label: '关联暴露面',
    disabled: false,
  },
  {
    name: 'surfaceAnalysis',
    label: '攻击面分析',
    disabled: false,
  },
]);
const tableConfig = reactive({
  uri: 'detail/getWeaknessList',
  params: {
    asmType: '',
    vulLevel: '',
    vulId: '',
    assetType: 'web',
    assetId: id,
  },
  tableAttr: {
    'max-height': '605px',
  },
  columns: [
    {
      label: '弱点名称',
      prop: 'vulName',
    },
    {
      label: '漏洞编号',
      prop: 'vulCode',
    },
    {
      label: '风险等级',
      prop: 'vulLevel',
      isReplace: true,
      obj: {
        0: '信息',
        1: '低危',
        2: '中危',
        3: '高危',
        4: '超危',
      },
      // render: (h, c) => {
      //   let obj = {
      //     0: '信息',
      //     1: '低危',
      //     2: '中危',
      //     3: '高危',
      //     4: '超危',
      //   }
      //   let val = obj[Number(c.row.vulLevel)]
      //   return h('div', { style: {} }, val)
      // },
    },
    {
      label: '弱点类型',
      prop: 'asmType',
    },
    {
      label: '发现时间',
      prop: 'insertTime',
    },
    {
      label: '弱点存在位置',
      prop: 'bugUrl',
    },
  ],
});
const dirList = ref([]);
const defaultProps = reactive({
  children: 'children',
  label: 'alias',
});
const surfaceAnalysisConfig = reactive({
  tableData: [],
  total: 0,
  pageNumber: 1,
  pageSize: 10,
});
const vulLevelData = reactive({
  0: '信息',
  1: '低危',
  2: '中危',
  3: '高危',
});
const titleBtn = computed(() => {
  const urlList = ['http', 'https'];
  let array = [
    {
      flag: 'url',
      tip: '访问',
      icon: 'vul-icon-url',
    },
  ];

  if (!urlList.includes(basicInfo.value.protocol)) {
    array = array.filter((el) => el.flag !== 'url');
  }
  return array;
});
const infoList = computed(() => {
  const { dataStatus, isAlive, createTime, updateTime, company } =
    basicInfo.value;

  const foundStatus = store.state.enum.assetStatus.find(
    (status) => status.type === parseInt(dataStatus),
  );

  return [
    {
      label: '更新状态',
      icon: 'vul-icon-type',
      type: 'tag',
      tag: foundStatus ? foundStatus.tag : 'warning',
      content: foundStatus ? foundStatus.value : '未知',
    },
    {
      label: '存活状态',
      icon: 'vul-icon-type',
      type: 'img',
      src: isAlive
        ? require(`@/static/images/icon/survival-${parseInt(isAlive)}.png`)
        : '',
    },
    {
      label: '首次发现',
      icon: 'vul-icon-time',
      content: createTime,
    },
    {
      label: '数据更新',
      icon: 'vul-icon-time',
      content: updateTime,
    },
    {
      label: '所属单位',
      icon: 'vul-icon-company',
      content: company,
    },
  ];
});
const baseInfo = computed(() => {
  const { title, name, ip, jarm } = detialInfo.value;
  return [
    {
      label: '网站标题',
      content: title,
    },
    {
      label: 'URL',
      type: 'url',
      content: name,
    },
    {
      label: '网站Banner',
      type: 'btn',
      content: '点击查看',
    },
    {
      label: '源IP',
      content: ip,
    },
    {
      label: 'jarm指纹',
      content: jarm,
    },
  ];
});
const icpInfo = computed(() => {
  if (!icpDetail.value) {
    return [];
  }
  const {
    websiteName,
    permitNumber,
    organizerType,
    organizerName,
    websiteDirector,
    registeredDomain,
  } = icpDetail.value;
  return [
    {
      label: '网站标题',
      content: websiteName,
    },
    {
      label: '备案许可证号',
      content: permitNumber,
    },
    {
      label: '主办单位性质',
      content: organizerType,
    },
    {
      label: '主办单位名称',
      content: organizerName,
    },
    {
      label: '网站负责人',
      content: websiteDirector,
    },
    {
      label: '备案域名',
      content: registeredDomain,
    },
  ];
});
const noticeList = computed(() => {
  return changeList.value.map(
    ({ fieldAlias, newValue, oldValue, changeTime, opType }) => {
      const btn = store.state.enum.changeStatus.find(
        ({ type }) => type === opType,
      );

      return {
        title: fieldAlias,
        content: opType === 3 ? oldValue : newValue,
        time: changeTime,
        type: btn ? btn.tag : '',
        typeText: btn ? btn.value : '',
      };
    },
  );
});
const expandableList = computed(() => {
  return certList.value.map((el: any) => {
    return {
      labelLength: 112,
      head: [
        {
          label: '证书指纹',
          content: el.certFingerprint,
        },
        {
          label: '是否过期',
          ...(el.certExpiredBln
            ? {
                content: '过期',
                contentType: 'danger',
                contentIcon: 'vul-icon-prompt-line',
              }
            : el.certExpiredBln == null
            ? {
                content: '--',
              }
            : {
                content: '未过期',
                contentType: 'success',
                contentIcon: 'vul-icon-success-a',
              }),
        },
      ],
      body: [
        {
          label: '序列号',
          content: el.certSerialNumber,
        },
        {
          label: '授权域名',
          content: el.certAuthorizedDomain,
        },
        {
          label: '开始时间',
          content: el.certNotBefore,
        },
        {
          label: '失效时间',
          content: el.certNotAfter,
        },
        {
          label: '颁发者名称',
          content: el.certIssuer,
        },
        {
          label: '使用者名称',
          content: el.certSubject,
        },
        {
          label: '颁发者邮箱',
          content: el.certIssuerEmail,
        },
        {
          label: '使用者邮箱',
          content: el.certSubjectEmail,
        },
        {
          label: '颁发者国家/地区',
          content: el.certIssuerLocation,
        },
        {
          label: '使用者国家/地区',
          content: el.certSubjectLocation,
        },
        {
          label: 'ssl的hostname',
          content: el.sslCertHostname,
        },
        {
          label: 'ssl证书文件url',
          content: el.sslCertFileUrl,
        },
        {
          label: '证书原文',
          content: el.cert,
          row: true,
        },
      ],
    };
  });
});
const expandableList2 = computed(() => {
  return [
    {
      labelLength: 112,
      head: [
        {
          label: '网站目录',
          content: '',
        },
      ],
      body: [
        {
          label: '目录结构',
          content: dirList.value,
          row: true,
        },
      ],
    },
  ];
});
const headersInfo = computed(() => {
  return {
    language: 'http',
    showLineNumbers: false,
    code: detialInfo.value.header,
  };
});
const modelList = computed(() => {
  const { products, protocol, port, os, ip } = detialInfo.value;

  const array = [
    {
      label: '产品',
      content: products?.map((product) => product.productName).join('、'),
    },
    {
      label: '协议',
      content: protocol,
    },
    {
      label: '端口',
      content: port + '',
    },
    {
      label: '操作系统',
      content: os,
    },
    {
      label: 'IP主机',
      content: ip?.replace(/,/g, '、'),
    },
  ];
  return array;
});
const rowList = computed(() => {
  return {
    assetId: id.value,
    assetType: category.value,
  };
});
onMounted(async () => {
  category.value = 'web';
  await getDetialById('detail/getWebById');
  await getLeftBaseInfo();
  await getAssetChanged();
  await getAnalysis();
  await getCertById();
  await getWebIcpInfo();
  await getWebDir();
  await getSurfaceAnalysisTableData();
});


const vulNameClick = (row) => {
  router.push({
    path: '/Assault/AttackList/assetVulDetail',
    query: {
      id: row.id,
    },
  });
};
const handleSizeChange = async (v) => {
  surfaceAnalysisConfig.pageSize = v;
  await getSurfaceAnalysisTableData();
};
const handleCurrentChange = async (v) => {
  surfaceAnalysisConfig.pageNumber = v;
  await getSurfaceAnalysisTableData();
};
const getSurfaceAnalysisTableData = async () => {
  let { pageNumber, pageSize } = surfaceAnalysisConfig;
  let params1 = {
    asmType: '',
    vulLevel: '',
    vulId: '',
    assetType: 'web',
    assetId: id.value,
    pageNumber,
    pageSize,
  };
  const { code, data } = await store.dispatch(
    'detail/getWeaknessList',
    params1,
  );
  if (code == 0) {
    let { list, total } = data;
    surfaceAnalysisConfig.tableData = list || [];
    surfaceAnalysisConfig.total = total;
  }
};
// const getDetialById=async (path)=> {
//   const { code, data } = await store.dispatch(path, id.value)
//   detialInfo.value = code === 0 ? data : {}
// }
const getCertById = async () => {
  const { code, data } = await store.dispatch('detail/getCertById', {
    webId: id.value,
  });
  certList.value = code === 0 ? data.list : {};
};
// 域名ICP备案信息
const getWebIcpInfo = async () => {
  const { code, data } = await store.dispatch('detail/getWebIcpInfo', id.value);
  icpDetail.value = code === 0 ? data : {};
};
// 网站目录
const getWebDir = async () => {
  const { code, data } = await store.dispatch('detail/getWebDir', id.value);
  dirList.value = code === 0 ? data.children : [];
};
</script>
<style lang="scss" scoped>
.info-table {
  margin-top: $-v-spacing-vertical-medium;
}

.cert-container {
  display: inline-block;
  height: 145px !important;
}

.base-one {
  margin-top: $-v-spacing-horizontal-base;

  .el-col {
    height: 210px;
  }
}

.over-flow {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.contentStyle {
  cursor: pointer;
  color: $-v-color-primary;
}

.self-pagination {
  margin-top: 16px;
  display: flex;
  justify-content: flex-end;

  ::v-deep .el-pagination__total {
    margin-right: 19px;
    color: rgb(60, 84, 113);
    font-size: 12px !important;
  }

  ::v-deep .el-select .el-input {
    width: 100px;
    margin: 0px 5px;
  }

  ::v-deep .el-select {
    width: 110px;
  }

  ::v-deep .el-input .el-input__inner {
    font-size: 13px;
  }

  ::v-deep .el-pagination__jump {
    margin-left: 5px;
    color: rgb(60, 84, 113);
    font-size: 12px !important;
  }

  ::v-deep .el-pagination__editor.el-input {
    width: 50px;
  }

  ::v-deep .el-select__wrapper {
    font-size: 12px !important;
  }

  ::v-deep .el-pagination__sizes {
    margin-left: 0;
  }

  ::v-deep .el-pager li {
    font-size: 12px !important;
  }
}

.surfaceAnalysisTable {
  ::v-deep thead th {
    font-weight: 500;
  }
}
</style>
